﻿@inherits LayoutComponentBase

@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment whe

@code{
	bool AllowEnterDirectlyInDevMode = Environment.GetEnvironmentVariable("AllowEnterDirectlyInDevMode") == "Yes";   //Warning:don't turn on it at server
}

@if (BlazorSession.Current.Browser == null)
{
	BlazorSession.Current.SetTimeout(10, StateHasChanged);
	return;
}

@if (viewmode == "connecting")
{
	<div style="display:flex;flex-direction:column;align-items:center;width:100%;padding:32px;">
		<div>
			Checking permission for @username ...
		</div>
	</div>

	return;
}

@if (viewmode == null)
{
	if (BlazorSession.Current.Browser.GetMemoryItem("LogonOK") as string != "OK")
	{
		if (AllowEnterDirectlyInDevMode && whe.EnvironmentName == "Development")
		{
			void LoginForDev()
			{
				BlazorSession.Current.Browser.SetMemoryItem("LogonOK", "OK");
			}

			<div style="display:flex;flex-direction:column;align-items:center;width:100%;padding:32px;">
				<h1>
					Development
				</h1>
				<div>
					In Development mode , you can use this app directly.
				</div>
				<div>
					In Production mode , you must login into linux via ssh localhost:22
				</div>
				<button class="btn btn-primary" style="margin:32px;width:100px;" @onclick="LoginForDev">
					OK
				</button>
			</div>
			return;
		}
		else
		{
			username = BlazorSession.Current.Browser.GetMemoryItem("console_username") as string;
			password = BlazorSession.Current.Browser.GetMemoryItem("console_password") as string;
			viewmode = "login";
		}
	}
}

@if (viewmode == "login")
{
	<style>
		.label_1 {
			display: inline-block;
			width: 100px;
			text-align: right;
		}
	</style>
	<div style="display:flex;flex-direction:column;align-items:center;width:100%;padding:32px;">
		<h1>BlazorLinuxAdmin</h1>
		<h3>OS : @Environment.OSVersion + @(Environment.Is64BitOperatingSystem?"64bit":"32bit")</h3>
		<EditForm Model="this">
			<span class="label_1">username:</span><InputText class="inp_username" @bind-Value="username" />
			<br />
			<span class="label_1">password:</span><InputText class="inp_password" type="password" @bind-Value="password" />
			<br />
			<span class="label_1"></span><button @onclick="DoLogin">Login</button>
		</EditForm>
		<br />
		<h4 style="color:red;text-align:center;">Warning<br />This application is no safe<br />Don't use it for public network</h4>
	</div>

	return;
}

@code{


	string viewmode = null;
	string username = "pi";
	string password = "raspberry";

	void DoLogin()
	{
		if (string.IsNullOrWhiteSpace(username))
		{
			BlazorSession.Current.Toast("Require username");
			BlazorSession.Current.EvalCode("document.querySelector('.inp_username').focus()");
			return;
		}
		if (string.IsNullOrWhiteSpace(password))
		{
			BlazorSession.Current.Toast("Require password");
			BlazorSession.Current.EvalCode("document.querySelector('.inp_password').focus()");
			return;
		}

		username = username.Trim();

		if (Environment.OSVersion.Platform == PlatformID.Unix)
		{
			DoLogin_Unix();
		}
		else if (Environment.OSVersion.Platform == PlatformID.Win32NT)
		{
			DoLogin_WinNT();
		}
		else
		{
			BlazorSession.Current.Alert("Error", "Not Support");
		}
	}

	void DoLogin_WinNT()
	{
		if (username.Contains("Administrator", StringComparison.OrdinalIgnoreCase))
		{
			BlazorSession.Current.Alert("Error", "Not allow Administrator, try another user.");
			return;
		}

		viewmode = "connecting";
		BlazorSession ses = BlazorSession.Current;
		ses.PostToRenderThread(delegate
		{
			using (var pc = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Machine))
			{
				bool isok = pc.ValidateCredentials(username, password);
				if (!isok)
				{
					viewmode = "login";
					BlazorSession.Current.Alert("Error", "Invalid Credentials");
					return;
				}

				var up = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(pc, username);
				var gp = System.DirectoryServices.AccountManagement.GroupPrincipal.FindByIdentity(pc, "Administrators");
				if (up == null || gp == null || !up.IsMemberOf(gp))
				{
					viewmode = "login";
					BlazorSession.Current.Alert("Error", "Require Administrators");
					return;
				}

				BlazorSession.Current.Browser.SetMemoryItem("LogonOK", "OK");
				viewmode = null;
			}
		});
		ses.PostToRenderThread(StateHasChanged);

	}

	void DoLogin_Unix()
	{

		Renci.SshNet.SshClient client = new Renci.SshNet.SshClient("localhost", username, password);

		viewmode = "connecting";

		BlazorSession ses = BlazorSession.Current;

		ses.PostToRenderThread(delegate
		{
			try
			{
				client.Connect();
			}
			catch (Exception x)
			{
				BlazorSession.Current.Alert("Error", x.ToString());
				viewmode = "login";
				StateHasChanged();
				return;
			}

			BlazorSession.Current.Browser.SetMemoryItem("console_username", username);
			BlazorSession.Current.Browser.SetMemoryItem("console_password", password);

			BlazorSession.Current.Browser.SetMemoryItem("LogonOK", "OK");
			viewmode = null;
			StateHasChanged();

			try
			{
				client.Disconnect();
				client.Dispose();
			}
			catch
			{

			}

		});

	}
}




@code{
	bool keepStateWhenSwitchPages = true;
}




@inject NavigationManager navmgr

@code{

	TimeSpan GetUrlMaxLifeSpan(string url)
	{
		if (url.Contains("/fetchdata")) // Let /fetachdata always refresh
			return TimeSpan.Zero;

		if (url.Contains("/counter"))   // Let /counter expires in 10 seconds
			return TimeSpan.FromSeconds(10);

		return TimeSpan.FromSeconds(-1);    //other pages never expires
	}

	class PageItem
	{
		public string Url;
		public RenderFragment PageBody;
		public DateTime StartTime = DateTime.Now;
		public DateTime ActiveTime = DateTime.Now;
		public TimeSpan MaxLifeSpan;
	}

	Dictionary<string, PageItem> bodymap = new Dictionary<string, PageItem>();

	int mainRenderCount = 0;
}

<div class="sidebar">
	<NavMenu />
</div>

<div class="main">


	@{

		bool currurlrendered = false;

		string currenturl = navmgr.Uri;

		if (keepStateWhenSwitchPages)
		{
			PageItem curritem;
			if (bodymap.TryGetValue(currenturl, out curritem))
			{
				curritem.ActiveTime = DateTime.Now;
			}
			else
			{
				curritem = new PageItem { Url = currenturl, PageBody = Body };
				curritem.MaxLifeSpan = GetUrlMaxLifeSpan(currenturl);
				if (curritem.MaxLifeSpan != TimeSpan.Zero)
				{
					bodymap[navmgr.Uri] = curritem;
				}
			}
		}
		else
		{
			bodymap.Clear();
		}

		mainRenderCount++;

	}

	@foreach (PageItem eachitem in bodymap.Values.Where(
  eachitem => eachitem.Url != currenturl && eachitem.MaxLifeSpan.TotalSeconds > 0 && DateTime.Now - eachitem.ActiveTime > eachitem.MaxLifeSpan))
	{
		bodymap.Remove(eachitem.Url);
	}

	<div class="top-row px-4">
		@foreach (PageItem eachitem in bodymap.Values)
		{

		}
		<EditForm Model="this">
			<label style="white-space: nowrap;"><InputCheckbox @bind-Value="keepStateWhenSwitchPages" />keepStateWhenSwitchPages</label>
		</EditForm>
	</div>

	@foreach (PageItem eachitem in bodymap.Values)
	{
		string pageurl = eachitem.Url;
		RenderFragment pagebody = eachitem.PageBody;

		string divstyle = "display:none";
		if (pageurl == currenturl)
		{
			divstyle = "";
			currurlrendered = true;
		}

		<div @key="pageurl" class="content px-4" style="@divstyle">
			@pagebody
		</div>
	}

	@if (!currurlrendered)
	{
		<div class="content px-4">
			@Body
		</div>
	}

</div>



